{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# OutputFixingParser\n",
    "\n",
    "`OutputFixingParser`는 출력 파싱 과정에서 발생할 수 있는 오류를 자동으로 수정하는 기능을 제공합니다. 이 파서는 기본적으로 다른 파서, 예를 들어 `PydanticOutputParser` 를 래핑하고, 이 파서가 처리할 수 없는 형식의 출력이나 오류를 반환할 경우, 추가적인 LLM 호출을 통해 오류를 수정하도록 설계되었습니다.\n",
    "\n",
    "이러한 접근 방식의 핵심은, 첫 번째 시도에서 스키마를 준수하지 않는 결과가 나올 경우, `OutputFixingParser` 가 자동으로 형식이 잘못된 출력을 인식하고, 이를 수정하기 위한 새로운 명령어와 함께 모델에 다시 제출한다는 것입니다. 이 과정에서, 수정을 위한 명령어는 오류를 정확히 지적하고, 올바른 형식으로 데이터를 재구성할 수 있도록 구체적인 지시를 포함해야 합니다.\n",
    "\n",
    "예를 들어, `PydanticOutputParser` 를 사용하여 특정 데이터 스키마를 준수하는 출력을 생성하려고 했지만, 일부 필드가 누락되었거나 데이터 유형이 잘못된 경우가 발생할 수 있습니다. 이때 `OutputFixingParser` 는 다음 단계로, 해당 오류를 수정하는 지시를 포함한 새로운 요청을 LLM에 제출합니다. LLM은 이 지시를 바탕으로 오류를 수정한 새로운 출력을 생성하게 됩니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# API KEY를 환경변수로 관리하기 위한 설정 파일\n",
    "from dotenv import load_dotenv\n",
    "\n",
    "# API KEY 정보로드\n",
    "load_dotenv()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# LangSmith 추적을 설정합니다. https://smith.langchain.com\n",
    "# !pip install langchain-teddynote\n",
    "from langchain_teddynote import logging\n",
    "\n",
    "# 프로젝트 이름을 입력합니다.\n",
    "logging.langsmith(\"CH03-OutputParser\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "from langchain.output_parsers import PydanticOutputParser\n",
    "from pydantic import BaseModel, Field\n",
    "from typing import List\n",
    "\n",
    "\n",
    "class Actor(BaseModel):\n",
    "    name: str = Field(description=\"name of an actor\")\n",
    "    film_names: List[str] = Field(description=\"list of names of films they starred in\")\n",
    "\n",
    "\n",
    "actor_query = \"Generate the filmography for a random actor.\"\n",
    "\n",
    "parser = PydanticOutputParser(pydantic_object=Actor)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(참고) 다음의 Cell 은 오류가 발생해야 **정상** 입니다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 잘못된 형식을 일부러 입력\n",
    "misformatted = \"{'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}\"\n",
    "\n",
    "# 잘못된 형식으로 입력된 데이터를 파싱하려고 시도\n",
    "parser.parse(misformatted)\n",
    "\n",
    "# 오류 출력"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`OutputFixingParser` 를 사용하여 잘못된 형식을 바로 잡도록 하겠습니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.output_parsers import OutputFixingParser\n",
    "\n",
    "new_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 잘못된 형식의 출력\n",
    "misformatted"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# OutputFixingParser 를 사용하여 잘못된 형식의 출력을 파싱\n",
    "actor = new_parser.parse(misformatted)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 파싱된 결과\n",
    "actor"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py-test",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
